package cn.com.anysdk.demo.controller;

import cn.com.anysdk.oss.api.IOssService;
import cn.com.anysdk.oss.api.UploadOptions;
import cn.com.anysdk.oss.config.AliyunOssConfig;
import cn.com.anysdk.oss.config.LocalFileSystemConfig;
import cn.com.anysdk.oss.exception.OssException;
import cn.com.anysdk.oss.factory.OssServiceFactory;
import com.aliyun.oss.OSS;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.FileOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Slf4j
@RestController
@RequestMapping("/api/oss")
public class AliyunOssController {

    @Autowired
    @Qualifier("aliyunOssService")
    private IOssService ossService;

    @Autowired
    private OSS ossClient;

    @Autowired
    private AliyunOssConfig aliyunOssConfig;

    @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public Map<String, Object> uploadFile(
            @RequestParam("file") MultipartFile file,
            @RequestParam(value = "isPublic", defaultValue = "true") boolean isPublic,
            @RequestParam(value = "path", required = false) String path) {
        try {
            Path tempFile = Files.createTempFile("upload-", file.getOriginalFilename());
            file.transferTo(tempFile.toFile());

            UploadOptions options = UploadOptions.publicFile();
            if (!isPublic) {
                options = UploadOptions.privateFile(3600L);
            }

            String objectKey = path != null ? path + "/" + file.getOriginalFilename()
                                          : "uploads/" + file.getOriginalFilename();

            String url = ossService.uploadFile(objectKey, tempFile.toFile(), options);
            Files.delete(tempFile);

            Map<String, Object> result = new HashMap<>();
            result.put("url", url);
            result.put("path", objectKey);
            result.put("name", file.getOriginalFilename());
            result.put("size", file.getSize());
            result.put("type", file.getContentType());
            result.put("isPublic", isPublic);
            result.put("uploadTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            return result;
        } catch (IOException e) {
            throw new OssException("Failed to upload file: " + e.getMessage(), e);
        }
    }

    @GetMapping("/files")
    public List<Map<String, Object>> getFiles() {
        List<Map<String, Object>> files = new ArrayList<>();
        try {
            // 使用OSS客户端获取文件列表
            ObjectListing objectListing = ossClient.listObjects(aliyunOssConfig.getBucketName());
            for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
                Map<String, Object> fileInfo = new HashMap<>();
                fileInfo.put("name", objectSummary.getKey());
                fileInfo.put("size", objectSummary.getSize());
                fileInfo.put("lastModified", objectSummary.getLastModified());
                fileInfo.put("url", ossService.getFileUrl(objectSummary.getKey()));
                fileInfo.put("path", objectSummary.getKey());
                fileInfo.put("type", getFileType(objectSummary.getKey()));
                fileInfo.put("uploadTime", objectSummary.getLastModified());
                files.add(fileInfo);
            }
        } catch (Exception e) {
            log.error("Failed to list files from OSS", e);
            throw new OssException("Failed to list files: " + e.getMessage(), e);
        }
        return files;
    }

    @DeleteMapping("/files/{path}")
    public Map<String, Object> deleteFile(@PathVariable("path") String path) {
        Map<String, Object> result = new HashMap<>();
        try {
            // 检查文件是否存在
            if (!ossService.doesObjectExist(path)) {
                result.put("success", false);
                result.put("message", "文件不存在");
                return result;
            }

            // 删除文件
            ossService.deleteFile(path);

            result.put("success", true);
            result.put("message", "文件删除成功");
            log.info("Successfully deleted file: {}", path);
        } catch (Exception e) {
            log.error("Failed to delete file: {}", path, e);
            result.put("success", false);
            result.put("message", "文件删除失败: " + e.getMessage());
            throw new OssException("Failed to delete file: " + e.getMessage(), e);
        }
        return result;
    }

    @PostMapping("/switch")
    public void switchProvider(@RequestBody Map<String, Object> config) {
        String provider = (String) config.get("provider");
        if ("aliyun".equals(provider)) {
            // 配置阿里云OSS
            AliyunOssConfig aliyunConfig = new AliyunOssConfig.Builder()
                    .endpoint((String) config.get("endpoint"))
                    .accessKeyId((String) config.get("accessKeyId"))
                    .accessKeySecret((String) config.get("accessKeySecret"))
                    .bucketName((String) config.get("bucketName"))
                    .isPrivate(false)
                    .build();

            // 创建新的OSS服务实例
            ossService = OssServiceFactory.createService(aliyunConfig);
        } else if ("local".equals(provider)) {
            // 配置本地文件系统
            LocalFileSystemConfig localConfig = new LocalFileSystemConfig();
            localConfig.setBasePath((String) config.get("basePath"));
            localConfig.setPrivate(false);

            // 创建新的OSS服务实例
            ossService = OssServiceFactory.createService(localConfig);
        }

        log.info("Switched OSS provider to: {}", provider);
    }

    @GetMapping("/download/{objectKey}")
    public void downloadFile(@PathVariable String objectKey) {
      try (InputStream inputStream = ossService.downloadFile(objectKey)){
            Path tempFile = Files.createTempFile("download-",objectKey);
            try(FileOutputStream fileOutputStream = new FileOutputStream(tempFile.toFile())) {
                byte[] buffer = new byte[1024];
                int byteRead;
               while ((byteRead = inputStream.read(buffer)) != -1) {
                   fileOutputStream.write(buffer,0,byteRead);
               }
               Files.delete(tempFile);
            }
      }catch (Exception e) {
          throw new OssException("Failed to download file: " + e.getMessage(), e);
      }
    }

    @GetMapping("/url/{objectKey}")
    public Map<String, String> getFileUrl(@PathVariable String objectKey) {
        String url = ossService.getFileUrl(objectKey);
        Map<String, String> result = new HashMap<>();
        result.put("url", url);
        return result;
    }

    @GetMapping("/exists/{objectKey}")
    public Map<String, Boolean> doesObjectExist(@PathVariable String objectKey) {
        boolean exists = ossService.doesObjectExist(objectKey);
        Map<String, Boolean> result = new HashMap<>();
        result.put("exists", exists);
        return result;
    }

    private String getFileType(String path) {
        String extension = path.substring(path.lastIndexOf(".") + 1).toLowerCase();
        return switch (extension) {
            case "jpg", "jpeg" -> "image/jpeg";
            case "png" -> "image/png";
            case "gif" -> "image/gif";
            case "pdf" -> "application/pdf";
            case "txt" -> "text/plain";
            case "html" -> "text/html";
            case "css" -> "text/css";
            case "js" -> "application/javascript";
            case "json" -> "application/json";
            case "xml" -> "application/xml";
            case "doc", "docx" -> "application/msword";
            case "xls", "xlsx" -> "application/vnd.ms-excel";
            case "ppt", "pptx" -> "application/vnd.ms-powerpoint";
            default -> "application/octet-stream";
        };
    }
}
